#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#include "esp_log.h"
#include "esp_console.h"
#include "esp_system.h"
#include "esp_sleep.h"
#include "esp_spi_flash.h"
#include "driver/rtc_io.h"
#include "driver/uart.h"
#include "driver/spi_master.h"
#include "driver/gpio.h"
#include "argtable3/argtable3.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "cmd_system.h"
#include "sdkconfig.h"

static const char *TAG = "cmd_system";

static void register_free(void);
static void register_heap(void);
static void register_version(void);
static void register_restart(void);
static void register_rst_pll(void);
static void register_tasks(void);

extern uint8_t enable;

extern spi_device_handle_t spi;

const cmd_t pll_init_cmds[]={
    {0x07, 0b00000000, 0x1},
    {0x08, 0b00000000, 0x1},
    {0x09, 0b00000000, 0x1},
    {0x0A, 0b01010101, 0x1},
    {0x0B, 0b10101100, 0x1},
    {0x0C, 0b11000000, 0x1},
    {0x0D, 0b00000000, 0x1},
    {0x0E, 0b01110000, 0x1},
    {0x0F, 0b00000000, 0x3},
    {0, 0, 0xff}
};

cmd_t pll_user_cmds[script_len+1]={
    {0, 0, 0xff}
};

cmd_t cmds_custom1[script_len+1]={
    {0x07, 0b00000000, 0x1},
    {0x08, 0b01000000, 0x1},
    {0x09, 0b00000000, 0x1},
    {0x0A, 0b01010110, 0x3},
    {0x0B, 0b10101100, 0x1},
    {0x0C, 0b00000000, 0x1},
    {0x0C, 0b01000000, 0x1},
    {0x0D, 0b00000000, 0x1},
    {0x0E, 0b01110000, 0x1},
    {0x0F, 0b00000000, 0x3},
    {0, 0, 0xff}
};

cmd_t cmds_custom2[script_len+1]={
    {0x07, 0b10000000, 0x1},
    {0x08, 0b10000000, 0x1},
    {0x09, 0b00000000, 0x1},
    {0x0A, 0b01010110, 0x3},
    {0x0B, 0b10101100, 0x1},
    {0x0C, 0b00000000, 0x1},
    {0x0C, 0b01000000, 0x1},
    {0x0D, 0b00000000, 0x1},
    {0x0E, 0b01110000, 0x1},
    {0x0F, 0b00000000, 0x3},
    {0, 0, 0xff}
};

cmd_t cmds_custom3[script_len+1]={
    {0x07, 0b00000000, 0x1},
    {0x08, 0b01000000, 0x1},
    {0x09, 0b00000000, 0x1},
    {0x0A, 0b01010110, 0x3},
    {0x0B, 0b10101100, 0x1},
    {0x0C, 0b00000000, 0x1},
    {0x0C, 0b11000000, 0x1},
    {0x0D, 0b00000000, 0x1},
    {0x0E, 0b01110000, 0x1},
    {0x0F, 0b00000000, 0x3},
    {0, 0, 0xff}
};

cmd_t cmds_custom4[script_len+1]={
    {0x07, 0b10000000, 0x1},
    {0x08, 0b10000000, 0x1},
    {0x09, 0b00000000, 0x1},
    {0x0A, 0b01010110, 0x3},
    {0x0B, 0b10101100, 0x1},
    {0x0C, 0b00000000, 0x1},
    {0x0C, 0b11000000, 0x1},
    {0x0D, 0b00000000, 0x1},
    {0x0E, 0b01110000, 0x1},
    {0x0F, 0b00000000, 0x3},
    {0, 0, 0xff}
};

void register_system_common(void)
{
    register_free();
    register_heap();
    register_version();
    register_restart();
    register_tasks();
}

void register_system(void)
{
    register_system_common();
    register_system_pll();
}

/* 'version' command */
static int get_version(int argc, char **argv)
{
    esp_chip_info_t info;
    esp_chip_info(&info);
    printf("IDF Version:%s\r\n", esp_get_idf_version());
    printf("Chip info:\r\n");
    printf("\tmodel:%s\r\n", info.model == CHIP_ESP32 ? "ESP32" : "Unknow");
    printf("\tcores:%d\r\n", info.cores);
    printf("\tfeature:%s%s%s%s%d%s\r\n",
           info.features & CHIP_FEATURE_WIFI_BGN ? "/802.11bgn" : "",
           info.features & CHIP_FEATURE_BLE ? "/BLE" : "",
           info.features & CHIP_FEATURE_BT ? "/BT" : "",
           info.features & CHIP_FEATURE_EMB_FLASH ? "/Embedded-Flash:" : "/External-Flash:",
           spi_flash_get_chip_size() / (1024 * 1024), " MB");
    printf("\trevision number:%d\r\n", info.revision);
    if (enable){
        printf("\tSuccessfully Power Up\r\n");
    } else {
        printf("\tNot Power Up Check Power Button\r\n");
    }
    return 0;
}

static void register_version(void)
{
    const esp_console_cmd_t cmd = {
        .command = "version",
        .help = "Get version of chip and SDK",
        .hint = NULL,
        .func = &get_version,
    };
    ESP_ERROR_CHECK( esp_console_cmd_register(&cmd) );
}

/** 'restart' command restarts the program */

static int restart(int argc, char **argv)
{
    ESP_LOGI(TAG, "Restarting");
    esp_restart();
}

static void register_restart(void)
{
    const esp_console_cmd_t cmd = {
        .command = "restart",
        .help = "Software reset of the chip",
        .hint = NULL,
        .func = &restart,
    };
    ESP_ERROR_CHECK( esp_console_cmd_register(&cmd) );
}

/** 'free' command prints available heap memory */

static int free_mem(int argc, char **argv)
{
    printf("%d\n", esp_get_free_heap_size());
    return 0;
}

static void register_free(void)
{
    const esp_console_cmd_t cmd = {
        .command = "free",
        .help = "Get the current size of free heap memory",
        .hint = NULL,
        .func = &free_mem,
    };
    ESP_ERROR_CHECK( esp_console_cmd_register(&cmd) );
}

/* 'heap' command prints minumum heap size */
static int heap_size(int argc, char **argv)
{
    uint32_t heap_size = heap_caps_get_minimum_free_size(MALLOC_CAP_DEFAULT);
    printf("min heap size: %u\n", heap_size);
    return 0;
}

static void register_heap(void)
{
    const esp_console_cmd_t heap_cmd = {
        .command = "heap",
        .help = "Get minimum size of free heap memory that was available during program execution",
        .hint = NULL,
        .func = &heap_size,
    };
    ESP_ERROR_CHECK( esp_console_cmd_register(&heap_cmd) );

}

static int tasks_info(int argc, char **argv)
{
    const size_t bytes_per_task = 40; /* see vTaskList description */
    char *task_list_buffer = malloc(uxTaskGetNumberOfTasks() * bytes_per_task);
    if (task_list_buffer == NULL) {
        ESP_LOGE(TAG, "failed to allocate buffer for vTaskList output");
        return 1;
    }
    fputs("Task Name\tStatus\tPrio\tHWM\tTask#", stdout);
#ifdef CONFIG_FREERTOS_VTASKLIST_INCLUDE_COREID
    fputs("\tAffinity", stdout);
#endif
    fputs("\n", stdout);
    vTaskList(task_list_buffer);
    fputs(task_list_buffer, stdout);
    free(task_list_buffer);
    return 0;
}

static void register_tasks(void)
{
    const esp_console_cmd_t cmd = {
        .command = "tasks",
        .help = "Get information about running tasks",
        .hint = NULL,
        .func = &tasks_info,
    };
    ESP_ERROR_CHECK( esp_console_cmd_register(&cmd) );
}

void PLL_write(uint8_t address, uint8_t data)
{
    esp_err_t ret;
    spi_transaction_t t;

    memset(&t, 0, sizeof(t));
    t.length=8;
    t.cmd=2;
    t.addr=address;
    t.flags = SPI_TRANS_USE_TXDATA;
    t.tx_data[0]=data;
    ret=spi_device_polling_transmit(spi, &t);
    assert(ret==ESP_OK);
}

uint32_t PLL_read(uint8_t address)
{
    esp_err_t ret;
    spi_transaction_t t;
    memset(&t, 0, sizeof(t));
    t.cmd=1;
    t.addr=address;
    t.length=8;
    t.rxlength=8;
    t.flags = SPI_TRANS_USE_RXDATA|SPI_TRANS_USE_TXDATA;
    ret=spi_device_polling_transmit(spi, &t);
    assert(ret==ESP_OK);
    return t.rx_data[0];
}

static int ready_hock(void){
    PLL_write(0x1F, 0x0);
    PLL_write(0x1F, 0xFF);
    PLL_write(0x1F, 0x0);
    ESP_LOGI(TAG, "Successful Flushed");
    return 0;
}

static int rst_pll(int argc, char **argv)
{
    uint16_t cmd=0;
    if (!enable) {
        ESP_LOGW(TAG, "Debugger hasn't been enabled");
        return 0;
    }
    gpio_set_level(PIN_NUM_RST, 1);
    vTaskDelay(10 / portTICK_RATE_MS);
    gpio_set_level(PIN_NUM_RST, 0);
    vTaskDelay(10 / portTICK_RATE_MS);
    gpio_set_level(PIN_NUM_RST, 1);
    vTaskDelay(10 / portTICK_RATE_MS);
    while (pll_init_cmds[cmd].hook!=0xff) {
        PLL_write(pll_init_cmds[cmd].addr, pll_init_cmds[cmd].data);
        if (pll_init_cmds[cmd].hook&0x2) {
            ready_hock();
            };
        cmd++;
    }
    ESP_LOGI(TAG, "Init Finish\n");
    cmd = 0;
    while (pll_init_cmds[cmd].hook!=0xff) {
        if(pll_init_cmds[cmd].hook&0x1){
            uint8_t t = (uint8_t)PLL_read(pll_init_cmds[cmd].addr);
            if(t == pll_init_cmds[cmd].data){
                ESP_LOGI(TAG, "Successful in checking addr: 0x%x, init File: 0x%x, reg: 0x%x", pll_init_cmds[cmd].addr, pll_init_cmds[cmd].data, t);
            } else {
                ESP_LOGW(TAG, "Failed in checking addr: 0x%x, init File: 0x%x, reg: 0x%x", pll_init_cmds[cmd].addr, pll_init_cmds[cmd].data, t);
            }
        }
        cmd++;
    }
    return 0;
}

static int flush(int argc, char **argv)
{
    if (!enable) {
        ESP_LOGW(TAG, "Debugger hasn't been enabled");
        return 0;
    }
    ready_hock();
    return 0;
}

static void register_rst_pll(void)
{
    const esp_console_cmd_t cmd = {
        .command = "rst_pll",
        .help = "Reset pll and load initial scripts",
        .hint = NULL,
        .func = &rst_pll
    };
    ESP_ERROR_CHECK( esp_console_cmd_register(&cmd) );
    const esp_console_cmd_t cmdflush = {
        .command = "flush",
        .help = "Flush Update",
        .hint = NULL,
        .func = &flush
    };
    ESP_ERROR_CHECK( esp_console_cmd_register(&cmdflush) );
}

static int write_script(int argc, char **argv)
{
    uint16_t cmd=0;
    if (!enable) {
        ESP_LOGW(TAG, "Debugger hasn't been enabled");
        return 0;
    }
    while (pll_user_cmds[cmd].hook!=0xff) {
        PLL_write(pll_user_cmds[cmd].addr, pll_user_cmds[cmd].data);
        if (pll_user_cmds[cmd].hook&0x2) ready_hock();
        cmd++;
    }
    cmd = 0;
    while (pll_user_cmds[cmd].hook!=0xff) {
        if(pll_user_cmds[cmd].hook&0x1){
            uint8_t t = (uint8_t)PLL_read(pll_user_cmds[cmd].addr);
            if(t == pll_user_cmds[cmd].data){
                ESP_LOGI(TAG, "Successful in checking addr: 0x%x, init File: 0x%x, reg: 0x%x", pll_user_cmds[cmd].addr, pll_user_cmds[cmd].data, t);
            } else {
                ESP_LOGW(TAG, "Failed in checking addr: 0x%x, init File: 0x%x, reg: 0x%x", pll_user_cmds[cmd].addr, pll_user_cmds[cmd].data, t);
            }
        }
        cmd++;
    }
    return 0;
}

static int write_script1(int argc, char **argv)
{
    uint16_t cmd=0;
    if (!enable) {
        ESP_LOGW(TAG, "Debugger hasn't been enabled");
        return 0;
    }
    cmd_t* sc_script = cmds_custom1;
    while (sc_script[cmd].hook!=0xff) {
        PLL_write(sc_script[cmd].addr, sc_script[cmd].data);
        if(sc_script[cmd].hook&0x1){
            uint8_t t = (uint8_t)PLL_read(sc_script[cmd].addr);
            if(t == sc_script[cmd].data){
                ESP_LOGI(TAG, "Successful in checking addr: 0x%x, init File: 0x%x, reg: 0x%x", sc_script[cmd].addr, sc_script[cmd].data, t);
            } else {
                ESP_LOGW(TAG, "Failed in checking addr: 0x%x, init File: 0x%x, reg: 0x%x", sc_script[cmd].addr, sc_script[cmd].data, t);
            }
        }
        if (sc_script[cmd].hook&0x2) ready_hock();
        cmd++;
    }
    return 0;
}

static int write_script2(int argc, char **argv)
{
    uint16_t cmd=0;
    if (!enable) {
        ESP_LOGW(TAG, "Debugger hasn't been enabled");
        return 0;
    }
    cmd_t* sc_script = cmds_custom2;
    while (sc_script[cmd].hook!=0xff) {
        PLL_write(sc_script[cmd].addr, sc_script[cmd].data);
        if(sc_script[cmd].hook&0x1){
            uint8_t t = (uint8_t)PLL_read(sc_script[cmd].addr);
            if(t == sc_script[cmd].data){
                ESP_LOGI(TAG, "Successful in checking addr: 0x%x, init File: 0x%x, reg: 0x%x", sc_script[cmd].addr, sc_script[cmd].data, t);
            } else {
                ESP_LOGW(TAG, "Failed in checking addr: 0x%x, init File: 0x%x, reg: 0x%x", sc_script[cmd].addr, sc_script[cmd].data, t);
            }
        }
        if (sc_script[cmd].hook&0x2) ready_hock();
        cmd++;
    }
    return 0;
}

static int write_script3(int argc, char **argv)
{
    uint16_t cmd=0;
    if (!enable) {
        ESP_LOGW(TAG, "Debugger hasn't been enabled");
        return 0;
    }
    cmd_t* sc_script = cmds_custom3;
    while (sc_script[cmd].hook!=0xff) {
        PLL_write(sc_script[cmd].addr, sc_script[cmd].data);
        if(sc_script[cmd].hook&0x1){
            uint8_t t = (uint8_t)PLL_read(sc_script[cmd].addr);
            if(t == sc_script[cmd].data){
                ESP_LOGI(TAG, "Successful in checking addr: 0x%x, init File: 0x%x, reg: 0x%x", sc_script[cmd].addr, sc_script[cmd].data, t);
            } else {
                ESP_LOGW(TAG, "Failed in checking addr: 0x%x, init File: 0x%x, reg: 0x%x", sc_script[cmd].addr, sc_script[cmd].data, t);
            }
        }
        if (sc_script[cmd].hook&0x2) ready_hock();
        cmd++;
    }
    return 0;
}

static int write_script4(int argc, char **argv)
{
    uint16_t cmd=0;
    if (!enable) {
        ESP_LOGW(TAG, "Debugger hasn't been enabled");
        return 0;
    }
    cmd_t* sc_script = cmds_custom4;
    while (sc_script[cmd].hook!=0xff) {
        PLL_write(sc_script[cmd].addr, sc_script[cmd].data);
        if(sc_script[cmd].hook&0x1){
            uint8_t t = (uint8_t)PLL_read(sc_script[cmd].addr);
            if(t == sc_script[cmd].data){
                ESP_LOGI(TAG, "Successful in checking addr: 0x%x, init File: 0x%x, reg: 0x%x", sc_script[cmd].addr, sc_script[cmd].data, t);
            } else {
                ESP_LOGW(TAG, "Failed in checking addr: 0x%x, init File: 0x%x, reg: 0x%x", sc_script[cmd].addr, sc_script[cmd].data, t);
            }
        }
        if (sc_script[cmd].hook&0x2) ready_hock();
        cmd++;
    }
    return 0;
}

static struct {
    struct arg_int *select;
    struct arg_end *end;
} view_args;

static int view_scripts(int argc, char **argv)
{
    uint16_t cmd=0;
    int nerrors = arg_parse(argc, argv, (void **) &view_args);
    if (nerrors != 0) {
        arg_print_errors(stderr, view_args.end, argv[0]);
        return 1;
    }
    if (view_args.select -> count) {
        cmd_t* sc_select;
        if (view_args.select->ival[0] == 0){
            sc_select = pll_init_cmds;
        } else if (view_args.select->ival[0] == 1) {
            sc_select = cmds_custom1;
        } else if (view_args.select->ival[0] == 2) {
            sc_select = cmds_custom2;
        } else if (view_args.select->ival[0] == 3) {
            sc_select = cmds_custom3;
        } else if (view_args.select->ival[0] == 4) {
            sc_select = cmds_custom4;
        } else if (view_args.select->ival[0] == 5) {
            sc_select = pll_user_cmds;
        } else {
            ESP_LOGW(TAG, "Invalid select");
            return 0;
        }
        while (sc_select[cmd].hook!=0xff) {
            ESP_LOGI(TAG, "%d\t| Addr: 0x%x\t| Reg: 0x%x\t| Flag: 0x%x", cmd, sc_select[cmd].addr, sc_select[cmd].data, sc_select[cmd].hook);
            cmd++;
        }
    }
    return 0;
}

static struct {
    struct arg_int *num;
    struct arg_int *addr;
    struct arg_int *data;
    struct arg_int *flag;
    struct arg_end *end;
} edit_args;

static int edit_script(int argc, char **argv)
{
    int nerrors = arg_parse(argc, argv, (void **) &edit_args);
    if (nerrors != 0) {
        arg_print_errors(stderr, edit_args.end, argv[0]);
        return 1;
    }
    if (edit_args.num -> count & edit_args.addr -> count & edit_args.data -> count & edit_args.flag -> count) {
        if (edit_args.flag->ival[0] == 0xff){
            if ((edit_args.num->ival[0] < script_len - 1) & (edit_args.num->ival[0] >= 0)){
                pll_user_cmds[edit_args.num->ival[0]].addr = 0;
                pll_user_cmds[edit_args.num->ival[0]].data = 0;
                pll_user_cmds[edit_args.num->ival[0]].hook = 0xff;
                ESP_LOGI(TAG, "Set %d to be end", edit_args.num->ival[0]);
            } else {
                ESP_LOGW(TAG, "Exceed max num whixh is %d", script_len - 1);
            }
        } else {
            if ((edit_args.num->ival[0] < script_len - 1) & (edit_args.num->ival[0] >= 0)){
                if (pll_user_cmds[edit_args.num->ival[0]].hook == 0xff){
                    ESP_LOGW(TAG, "Overwrite end bit! Overwrite end bit! Overwrite end bit!");
                }
                pll_user_cmds[edit_args.num->ival[0]].addr = edit_args.addr->ival[0];
                pll_user_cmds[edit_args.num->ival[0]].data = edit_args.data->ival[0];
                pll_user_cmds[edit_args.num->ival[0]].hook = edit_args.flag->ival[0];
                ESP_LOGI(TAG, "Set %d to be {Addr: 0x%x |Reg: 0x%x | Flag: 0x%x}", edit_args.num->ival[0], edit_args.addr->ival[0], edit_args.data->ival[0], edit_args.num->ival[0]);
            } else {
                ESP_LOGW(TAG, "Exceed max num whixh is %d", script_len - 1);
            }
        }
    } else {
        ESP_LOGW(TAG, "Check Parameters!");
    }
    return 0;
}

static struct {
    struct arg_int *addr;
    struct arg_end *end;
} read_args;

static int pll_read_data(int argc, char **argv)
{
    if (!enable) {
        ESP_LOGW(TAG, "Debugger hasn't been enabled");
        return 0;
    }
    int nerrors = arg_parse(argc, argv, (void **) &read_args);
    if (nerrors != 0) {
        arg_print_errors(stderr, read_args.end, argv[0]);
        return 1;
    }
    if (read_args.addr -> count) {
        uint8_t data = PLL_read(read_args.addr->ival[0]);
        ESP_LOGI(TAG, "Read Address (0x%x): 0x%x", read_args.addr->ival[0], data);
    } else {
        ESP_LOGW(TAG, "Supply the address!");
    }
    return 0;
}

static struct {
    struct arg_int *addr;
    struct arg_int *data;
    struct arg_int *flag;
    struct arg_end *end;
} write_check_args;

static int pll_write_check_data(int argc, char **argv)
{
    if (!enable) {
        ESP_LOGW(TAG, "Debugger hasn't been enabled");
        return 0;
    }
    int nerrors = arg_parse(argc, argv, (void **) &write_check_args);
    if (nerrors != 0) {
        arg_print_errors(stderr, write_check_args.end, argv[0]);
        return 1;
    }
    if (write_check_args.addr -> count && write_check_args.data -> count) {
        PLL_write(write_check_args.addr->ival[0], write_check_args.data->ival[0]);
    } else {
        ESP_LOGW(TAG, "Supply the address and data together");
    }
    if (write_check_args.flag -> count){
        if ((write_check_args.flag->ival[0]) & 0x2) {
            ready_hock();
        }
        if ((write_check_args.flag->ival[0]) & 0x1) {
            uint8_t t = (uint8_t)PLL_read(write_check_args.addr->ival[0]);
            if (t == write_check_args.data->ival[0]) ESP_LOGI(TAG, "Successful in checking addr: 0x%x, write: 0x%x, reg: 0x%x", write_check_args.addr->ival[0], write_check_args.data->ival[0], t);
            else ESP_LOGW(TAG, "Failed in checking addr: 0x%x, write: 0x%x, reg: 0x%x", write_check_args.addr->ival[0], write_check_args.data->ival[0], t);
        }
    }
    return 0;
}

void register_system_pll(void)
{
    register_rst_pll();

    write_check_args.addr =
        arg_int1("a", "address", "<a>", "Address to write in");
    write_check_args.data =
        arg_int1("d", "data", "<d>", "Data to write");
    write_check_args.flag =
        arg_int1("f", "flag", "<0-3>", "Post Hook Flag: \r\n\t Set Bit1: Flush READY reg \r\n\t Set Bit0: Check after write");
    write_check_args.end = arg_end(3);

    const esp_console_cmd_t write_check_cmd = {
        .command = "pll_write",
        .help = "Write PLL Reg Using SPI and Check it",
        .hint = NULL,
        .func = &pll_write_check_data,
        .argtable = &write_check_args
    };
    ESP_ERROR_CHECK( esp_console_cmd_register(&write_check_cmd) );

    read_args.addr =
        arg_int1("a", "address", "<a>", "Address to read");
    read_args.end = arg_end(1);

    const esp_console_cmd_t read_cmd = {
        .command = "pll_read",
        .help = "Read PLL Reg Using SPI",
        .hint = NULL,
        .func = &pll_read_data,
        .argtable = &read_args
    };
    ESP_ERROR_CHECK( esp_console_cmd_register(&read_cmd) );

    view_args.select =
        arg_int1("s", "select", "<0-5>", "Which script to show (0 -> init script, 5-> user script, 1-4 -> custom command)");
    view_args.end = arg_end(1);

    const esp_console_cmd_t view_cmd = {
        .command = "view_script",
        .help = "view script",
        .hint = NULL,
        .func = &view_scripts,
        .argtable = &view_args
    };
    ESP_ERROR_CHECK( esp_console_cmd_register(&view_cmd) );

    edit_args.num =
        arg_int1("n", "num", "<n>", "Index to edit");
    edit_args.addr =
        arg_int1("a", "addr", "<n>", "Reg address");
    edit_args.data =
        arg_int1("d", "data", "<n>", "Reg data");
    edit_args.flag =
        arg_int1("f", "flag", "<n>", "Hook Flag: \r\n\t Set Bit1: Flush READY reg \r\n\t Set Bit0: Check after write \r\n\t Set All To 1(0xFF): End flag");
    edit_args.end = arg_end(4);

    const esp_console_cmd_t edit_cmd = {
        .command = "edit_script",
        .help = "edit script",
        .hint = NULL,
        .func = &edit_script,
        .argtable = &edit_args
    };
    ESP_ERROR_CHECK( esp_console_cmd_register(&edit_cmd) );

    const esp_console_cmd_t write_s_cmd = {
        .command = "write_script",
        .help = "write user script",
        .hint = NULL,
        .func = &write_script
    };
    ESP_ERROR_CHECK( esp_console_cmd_register(&write_s_cmd) );

    const esp_console_cmd_t write_s_cmd1 = {
        .command = "pll_int_auto",
        .help = "pll_int_auto (custom script1)",
        .hint = NULL,
        .func = &write_script1
    };
    ESP_ERROR_CHECK( esp_console_cmd_register(&write_s_cmd1) );

    const esp_console_cmd_t write_s_cmd2 = {
        .command = "pll_int_cpfd",
        .help = "pll_int_cpfd (custom script2)",
        .hint = NULL,
        .func = &write_script2
    };
    ESP_ERROR_CHECK( esp_console_cmd_register(&write_s_cmd2) );

    const esp_console_cmd_t write_s_cmd3 = {
        .command = "pll_frac_auto",
        .help = "pll_frac_auto (custom script3)",
        .hint = NULL,
        .func = &write_script3
    };
    ESP_ERROR_CHECK( esp_console_cmd_register(&write_s_cmd3) );

    const esp_console_cmd_t write_s_cmd4 = {
        .command = "pll_frac_cpfd",
        .help = "pll_frac_cpfd (custom script4)",
        .hint = NULL,
        .func = &write_script4
    };
    ESP_ERROR_CHECK( esp_console_cmd_register(&write_s_cmd4) );
}
